<template>
  <div>
    <div style="text-align: right">
      <el-checkbox v-model="value.rawMode" style="margin-right: 10px;" label="raw" @change="handleRawCheckboxChange" />
      <el-button-group style="margin-top: 0px; margin-right: 12px; margin-bottom: 4px;">
        <el-tooltip :open-delay="500" content="发送" placement="top" style="margin-right: 6px;">
          <el-button icon="el-icon-position" size="mini" type="success" @click="handleSend">发送</el-button>
        </el-tooltip>
        <el-tooltip :open-delay="500" content="历史记录" placement="top">
          <el-button :disabled="element.id===undefined" icon="el-icon-link" size="mini" type="info" @click="handleHistory" />
        </el-tooltip>
        <el-tooltip content="导入 cURL" placement="top" :open-delay="500">
          <el-button type="primary" icon-class="skill" size="mini" @click="handleImportCurl"><svg-icon icon-class="import" /></el-button>
        </el-tooltip>
        <el-tooltip content="导出性能测试脚本" placement="top" :open-delay="500">
          <el-button :disabled="element.id===undefined" type="primary" icon-class="skill" size="mini" @click="handleExport"><svg-icon icon-class="export" /></el-button>
        </el-tooltip>
        <el-tooltip content="保存" placement="top" :open-delay="500">
          <el-button type="primary" icon-class="skill" size="mini" @click="saveElement"><svg-icon icon-class="save" /></el-button>
        </el-tooltip>
      </el-button-group>
    </div>
    <el-card shadow="hover">
      <el-alert style="margin-bottom: 10px" title="HTTP 接口定义" type="info" close-text="Get!">
        <div>1、接口名称：给每个接口起一个合理的名字更容易记；</div>
        <div>2、接口方法：目前支持 POST，GET，PUT、DELETE、BINARY（multipart/form-data 文件上传）</div>
        <div>3、URL：接口的 URL 地址</div>
        <div>4、请求参数：请求参数需要分别输入 Headers，URL Params，Body，Cookies，断言。其中:</div>
        <ul>
          <li>参数名【必填】：参数名称（key）</li>
          <li>参数描述：简述该参数的作用或取值范围，方便理解</li>
          <li>示例值【必填】：参数值（value）的示例</li>
          <li>参数类型：参数类型，如 String、int、file、json 等</li>
          <li>必填：该字段在请求中是否为必填项</li>
        </ul>
      </el-alert>
      <el-form ref="element" size="small" class="demo-table-expand" :rules="rules" label-width="8.4%" label-position="left" :model="element">
        <el-form-item prop="name" label="接口名称">
          <el-input v-model="element.name" placeholder="请输入名称" :class="activeName" />
        </el-form-item>
        <el-row>
          <el-col :span="2">
            <el-form-item prop="method" label="" label-width="0px">
              <el-select v-model="element.method" placeholder="请选择">
                <el-option
                  v-for="item in methodOptions"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item label="" label-width="0px" prop="host">
              <el-input
                v-model="element.host"
                placeholder="请输入 HOST"
              />
            </el-form-item>
          </el-col>
          <el-col :span="16">
            <el-form-item label="" label-width="0px" prop="uri">
              <el-input
                v-model="element.uri"
                placeholder="请输入 URI"
              />
            </el-form-item>
          </el-col>
          <el-col :span="2">
            <el-form-item prop="extra1" label="" label-width="0px">
              <template>
                <el-select v-model="element.extra1" placeholder="请选择" @change="handleChangeExtra1($event)">
                  <el-option
                    v-for="item in extraOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  />
                </el-select>
              </template>
            </el-form-item>
          </el-col>
        </el-row>

        <el-card shadow="box-card">
          <div style="margin-top: -10px; margin-bottom: -5px; margin-right: 85px; text-align: right;">
            <el-button-group style="z-index:1000; position:absolute;">
              <el-button size="mini" type="primary" @click="handleImportJson">导入 Json</el-button>
            </el-button-group>
          </div>
          <el-tabs v-model="kindActiveName" @tab-click="handleTabClick">
            <el-tab-pane label="Headers" name="Headers" />
            <el-tab-pane label="Cookies" name="Cookies" />
            <el-tab-pane label="URL Params" name="Params" />
            <el-tab-pane label="Body" name="Body" />
            <el-tab-pane label="响应" name="Assert" />
            <el-tab-pane label="Mock" name="Mock" />
          </el-tabs>
          <!-- Headers -->
          <div v-if="kindActiveName === 'Headers'">
            <div v-if="!value.rawMode" style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
              <s-json-schema-editor
                :key="headerSchemaKey"
                style="margin-top: 10px"
                :schema.sync="headerSchema"
                :show-edit="false"
                :show-setting="false"
                :show-default-value="true"
                :is-mock="false"
                :is-form="element.extra1 === 'FORM'"
              />
            </div>
            <div v-else style="border:solid 1px #dfe4ed;" class="json-editor">
              <json-editor ref="headerJsonEditor" :key="headerSchemaKey" v-model="headerSchema" />
            </div>
          </div>

          <!-- cookies-->
          <div v-if="kindActiveName === 'Cookies'">
            <div v-if="!value.rawMode" style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
              <s-json-schema-editor
                :key="cookiesSchemaKey"
                style="margin-top: 10px"
                :schema.sync="cookiesSchema"
                :show-edit="false"
                :show-setting="false"
                :show-default-value="true"
                :is-mock="false"
                :is-form="element.extra1 === 'FORM'"
              />
            </div>
            <div v-else style="border:solid 1px #dfe4ed;" class="json-editor">
              <json-editor ref="cookiesJsonEditor" :key="cookiesSchemaKey" v-model="cookiesSchema" />
            </div>
          </div>

          <!-- URL Params -->
          <div v-if="kindActiveName === 'Params'">
            <div v-if="!value.rawMode" style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
              <s-json-schema-editor
                :key="paramsSchemaKey"
                style="margin-top: 10px"
                :schema.sync="paramsSchema"
                :show-edit="false"
                :show-setting="false"
                :show-default-value="true"
                :is-mock="false"
                :is-form="element.extra1 === 'FORM'"
              />
            </div>
            <div v-else style="border:solid 1px #dfe4ed;" class="json-editor">
              <json-editor ref="paramsJsonEditor" :key="paramsSchemaKey" v-model="paramsSchema" />
            </div>
          </div>

          <!-- body -->
          <div v-if="kindActiveName === 'Body'">
            <div v-if="!value.rawMode" style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
              <s-json-schema-editor
                :key="bodySchemaKey"
                style="margin-top: 10px"
                :schema.sync="bodySchema"
                :show-edit="false"
                :show-setting="false"
                :show-default-value="true"
                :is-mock="false"
                :is-form="element.extra1 === 'FORM'"
              />
            </div>
            <div v-else style="border:solid 1px #dfe4ed;" class="json-editor">
              <json-editor ref="bodyJsonEditor" :key="bodySchemaKey" v-model="bodySchema" />
            </div>
          </div>

          <!-- assert -->
          <div v-if="kindActiveName === 'Assert'">
            <div v-if="!value.rawMode" style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
              <s-json-schema-editor
                :key="assertSchemaKey"
                style="margin-top: 10px"
                :schema.sync="assertSchema"
                :show-edit="false"
                :show-setting="false"
                :show-default-value="true"
                :is-mock="false"
                :is-form="element.extra1 === 'FORM'"
              />
            </div>
            <div v-else style="border:solid 1px #dfe4ed;" class="json-editor">
              <json-editor ref="assertJsonEditor" :key="assertSchemaKey" v-model="assertSchema" />
            </div>
          </div>

          <!-- mock -->
          <div v-if="kindActiveName === 'Mock'">
            <div v-if="!value.rawMode" style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
              <div style="text-align: right">
                <el-tooltip :open-delay="500" class="item" content="添加期望" effect="dark" placement="top-start">
                  <el-button circle icon="el-icon-plus" size="mini" style="margin: 5px;" type="primary" @click="handleAddDesire()" />
                </el-tooltip>
              </div>
              <el-table :data="mocksData" border size="mini">
                <el-table-column align="center" label="编号" type="index" width="45" />
                <el-table-column label="期望名称" min-width="30%" prop="name">
                  <template v-slot="{row}">
                    {{ row.name }}
                  </template>
                </el-table-column>
                <el-table-column label="条件" min-width="50%" prop="conditions">
                  <template v-slot="{row}">
                    <div v-for="item in row.conditions" :key="item.id">
                      {{ conditionsToStr(item) }}
                    </div>
                  </template>
                </el-table-column>
                <el-table-column align="center" label="操作" width="100px">
                  <template v-slot="scope">
                    <el-tooltip :open-delay="500" :tabindex="-1" content="编辑期望" placement="top">
                      <el-button circle size="mini" type="primary" @click="handleEditDesire(scope.$index)"><i class="el-icon-edit-outline" /></el-button>
                    </el-tooltip>
                    <el-tooltip :open-delay="500" :tabindex="-1" content="删除期望" placement="top">
                      <el-button circle size="mini" type="danger" @click="delDesireTableRow(scope.$index)"><i class="el-icon-delete" /></el-button>
                    </el-tooltip>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </div>
        </el-card>

        <!-- 调试信息 -->
        <el-card shadow="box-card" style="margin-top: 10px;">
          <div style="font-size: 14px; margin-top: -13px; margin-bottom: 2px;">调试信息</div>
          <div style="height: auto; min-height: 300px; border:solid 1px #dfe4ed;">
            <div>response:</div>
            <div>{{ debugApiLog.response.log }}</div>
            <div>request:</div>
            <div>{{ debugApiLog.request.log }}</div>
          </div>
        </el-card>
      </el-form>
    </el-card>

    <!-- 导入 Json-->
    <el-dialog title="导入 Json" :visible.sync="dialogFormVisible" width="800px" :close-on-click-modal="false">
      <el-form ref="dataForm" :rules="rules" label-position="right" label-width="100px">
        <div style="border:solid 1px #dfe4ed;" class="json-editor">
          <json-editor ref="importJsonEditor" :key="importJsonStrKey" v-model="importJsonStr" />
        </div>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="importJson">导 入</el-button>
      </div>
    </el-dialog>

    <!-- 导入 cURL -->
    <el-dialog title="导入 cURL" :visible.sync="importCurlDialogFormVisible" width="800px" :close-on-click-modal="false">
      <el-form ref="dataForm" :rules="rules" label-position="right" label-width="100px">
        <div>
          <el-input v-model="importCurlTextarea" type="textarea" :rows="15" placeholder="请粘贴 cURL 内容，例如：curl --location --request GET --url http://www.baidu.com" />
        </div>
        <div style="margin-top: 5px;">
          <el-switch v-model="ignoreGenericHeader" inactive-text="忽略通用 Header" style="zoom: 0.9; float: left;" />
          <div style="zoom: 0.9; float: left; margin-left: 5px; margin-top: 2px;">将忽略 User-Agent、Referer 等通用 Header</div>
        </div>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="importCurlDialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="importCurl">导 入</el-button>
      </div>
    </el-dialog>

    <!-- 导出性能测试脚本 -->
    <el-dialog title="导出性能测试脚本" :visible.sync="exportDialogFormVisible" width="800px" :close-on-click-modal="false">
      <div style="margin-bottom: 3px; text-align: right;">
        <el-button-group>
          <el-button size="mini" type="primary" @click="handleExportCopy($event)">复制</el-button>
        </el-button-group>
      </div>
      <div>
        <el-input v-model="exportTextarea" type="textarea" :rows="15" />
      </div>
    </el-dialog>

    <!-- 期望 -->
    <el-dialog :visible.sync="dialogFormDesireVisible" title="期望" width="1000px" :close-on-click-modal="false">
      <el-form ref="tmpDesireForm" :model="tmpDesire" :rules="desireRules" label-position="right" label-width="140px">
        <el-form-item label="期望名称" prop="name">
          <el-input v-model="tmpDesire.name" placeholder="请输入期望名称" />
        </el-form-item>
        <el-form-item label="参数条件">
          <el-table ref="stepsTable" :data="tmpDesire.conditions" border max-height="250" size="mini">
            <el-table-column align="center" label="编号" type="index" width="60" />
            <el-table-column label="参数位置" min-width="50%" prop="step">
              <template v-slot="scope">
                <el-select v-model="scope.row.location" placeholder="请选择">
                  <el-option
                    v-for="item in locationOptions"
                    :key="item.value"
                    :disabled="item.disabled"
                    :label="item.label"
                    :value="item.value"
                  />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="参数名" min-width="40%" prop="result">
              <template v-slot="scope">
                <el-input v-if="scope.$index !== tmpDesire.conditions.length - 1" v-model="scope.row.name" autosize class="item" />
                <el-input v-if="scope.$index === tmpDesire.conditions.length - 1" v-model="scope.row.name" autosize class="item" @input="newConditionsTableRow()" />
              </template>
            </el-table-column>
            <el-table-column label="比较" min-width="50%" prop="conditions">
              <template v-slot="scope">
                <el-select v-model="scope.row.comparison" placeholder="请选择" @change="handleChangeComparison(scope.row, $event)">
                  <el-option
                    v-for="item in comparisonOptions"
                    :key="item.value"
                    :disabled="item.disabled"
                    :label="item.label"
                    :value="item.value"
                  />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="参数值" min-width="50%" prop="conditions">
              <template v-slot="scope">
                <el-input v-if="scope.$index !== tmpDesire.conditions.length - 1" v-model="scope.row.value" :disabled="scope.row.comparison === 'exists' || scope.row.comparison === 'not_exist'" autosize class="item" />
                <el-input v-if="scope.$index === tmpDesire.conditions.length - 1" v-model="scope.row.value" :disabled="scope.row.comparison === 'exists' || scope.row.comparison === 'not_exist'" autosize class="item" @input="newConditionsTableRow()" />
              </template>
            </el-table-column>
            <el-table-column align="center" label="操作" width="80">
              <template v-slot="scope">
                <el-tooltip v-if="scope.$index !== tmpDesire.conditions.length - 1" :open-delay="500" :tabindex="-1" content="删除" placement="top">
                  <span class="icon-wrapper"><i class="el-icon-close icon-style" @click="delConditionsTableRow(scope.$index)" /></span>
                </el-tooltip>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
        <el-form-item label="返回 HTTP 状态码" prop="responseCode">
          <el-input v-model="tmpDesire.responseCode" placeholder="请输入返回 HTTP 状态码" />
        </el-form-item>
        <el-form-item label="返回 Body 类型" prop="responseType">
          <el-select v-model="tmpDesire.responseType" placeholder="请选择">
            <el-option
              v-for="item in responseTypeOptions"
              :key="item.value"
              :disabled="item.disabled"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="返回 Body" prop="responseBody">
          <el-input v-model="tmpDesire.responseBody" :rows="17" placeholder="请输入返回 Body" size="mini" style="width: 100%" type="textarea" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormDesireVisible = false">取 消</el-button>
        <el-button type="primary" @click="addDesire">确 定</el-button>
      </div>
    </el-dialog>

    <el-dialog :visible.sync="historyDialogFormVisible" title="历史记录" width="1200px" :close-on-click-modal="false">
      <api-history-component
        ref="apiHistoryComponent"
        @dblclickResultRow="dblclickResultRow"
      />
    </el-dialog>
  </div>
</template>
<style lang="scss" scoped>
.json-editor {
  text-align-last: left;
  // width: 100%;
  // height: 100%;
  position: relative;

  ::v-deep {
    .CodeMirror {
      height: auto;
      min-height: 300px;
    }

    .CodeMirror-scroll {
      min-height: 300px;
    }

    .cm-s-rubyblue span.cm-string {
      color: #F08047;
    }
  }
}
</style>

<script>
import clip from '@/utils/clipboard' // use clipboard directly
import { deepClone } from '@/utils'
import 'splitpanes/dist/splitpanes.css'
import { apiDebug, create, getApiDebugStatus, selectById as apiSelectById, update, apiCurlImport, apiExport } from '@/api/functional_test/test_data_manage/api'
import GenerateSchema from 'generate-schema'
import JsonEditor from '@/components/JsonEditor'
import { setSchemaDefaultValue } from '@/utils/generateSchemaBoost'
import ApiHistoryComponent from '@/components/functional_test/History/apiHistory'

export default {
  components: { JsonEditor, ApiHistoryComponent },
  props: {
    value: {
      type: Object,
      default() {
        return {
          rawMode: false // raw模式
        }
      }
    },
    debugEnv: { // 调试使用的环境
      type: String,
      default: ''
    },
    debugAgentId: { // 调试使用的环境
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      kindActiveName: 'Body',
      eType: 11, // 元素类型
      activeName: null, // 当前激活的 tab 名称
      eTitle: 'HTTP 接口',
      catalog: {}, // catalog 对象
      element: {}, // element 对象
      dialogFormVisible: false, // 导入 json 弹窗
      importCurlDialogFormVisible: false, // 导入 curl 弹窗
      importCurlTextarea: '', // 导入 curl textarea
      exportDialogFormVisible: false, // 导出性能测试脚本 弹窗
      exportTextarea: '', // 导出文本框
      ignoreGenericHeader: true, // 是否忽略通用请求头
      dialogFormDesireVisible: false, // 期望 弹窗
      tmpDesire: {}, // 期望临时对象
      tmpDesireIndex: -1, // 期望临时对象索引（-1 代表新增期望）
      headerSchema: undefined, // header json schema
      headerSchemaKey: undefined, // header json schema key (用于刷新json editor、s-json-schema-editor)
      cookiesSchema: undefined, // cookies json schema
      cookiesSchemaKey: undefined, // cookies json schema key (用于刷新json editor、s-json-schema-editor)
      paramsSchema: undefined, // params json schema
      paramsSchemaKey: undefined, // params json schema key (用于刷新json editor、s-json-schema-editor)
      bodySchema: undefined, // body json schema
      bodySchemaKey: undefined, // body json schema key (用于刷新json editor、s-json-schema-editor)
      assertSchema: undefined, // assert json schema
      assertSchemaKey: undefined, // assert json schema key (用于刷新json editor、s-json-schema-editor)
      mocksData: [], // mock 数据
      importJsonStr: {}, // 导入的json
      importJsonStrKey: Date.now(), // 导入的json key
      historyDialogFormVisible: false, // 历史记录弹窗
      debugApiLog: {}, // 调试结果
      rules: {
        name: [
          { required: true, message: 'HTTP 接口名称不能为空', trigger: 'blur' },
          { max: 255, message: 'HTTP 接口名称长度不能超过 255 个字符', trigger: 'blur' }
        ],
        uri: [
          { required: true, message: 'URI 不能为空', trigger: 'blur' },
          { max: 255, message: 'URI 长度不能超过 255 个字符', trigger: 'blur' }
        ],
        host: [
          { required: true, message: 'HOST 不能为空', trigger: 'blur' },
          { max: 100, message: 'HOST 长度不能超过 100 个字符', trigger: 'blur' }
        ]
      },
      desireRules: {
        name: [
          { required: true, message: '期望名称不能为空', trigger: 'blur' },
          { max: 50, message: '期望名称长度不能超过 50 个字符', trigger: 'blur' }
        ],
        responseCode: [
          { required: true, message: '返回 HTTP 状态码不能为空', trigger: 'blur' },
          { max: 5, message: '返回 HTTP 状态码长度不能超过 5 个字符', trigger: 'blur' }
        ],
        responseType: [
          { required: true, message: '返回 Body 类型不能为空', trigger: 'blur' },
          { max: 10, message: '返回 Body 类型长度不能超过 10 个字符', trigger: 'blur' }
        ]
      },
      methodOptions: [
        {
          value: 'POST',
          label: 'POST'
        }, {
          value: 'GET',
          label: 'GET'
        }, {
          value: 'PUT',
          label: 'PUT'
        }, {
          value: 'DELETE',
          label: 'DELETE'
        }, {
          value: 'BINARY',
          label: 'BINARY'
        }],
      extraOptions: [
        {
          value: 'JSON',
          label: 'JSON'
        }, {
          value: 'FORM',
          label: 'FORM'
        }],
      locationOptions: [
        {
          value: 'query',
          label: 'query'
        }, {
          value: 'path',
          label: 'path'
        }, {
          value: 'header',
          label: 'header'
        }, {
          value: 'cookie',
          label: 'cookie'
        }, {
          value: 'body',
          label: 'body'
        }
      ],
      comparisonOptions: [
        {
          value: 'equal',
          label: '等于'
        }, {
          value: 'not_equal',
          label: '不等于'
        }, {
          value: 'is_above',
          label: '大于'
        }, {
          value: 'is_atLeast',
          label: '大于或等于'
        }, {
          value: 'is_below',
          label: '小于'
        }, {
          value: 'is_at_most',
          label: '小于或等于'
        }, {
          value: 'include',
          label: '包含'
        }, {
          value: 'not_include',
          label: '不包含'
        }, {
          value: 'match',
          label: '正则匹配'
        }, {
          value: 'exists',
          label: '存在'
        }, {
          value: 'not_exist',
          label: '不存在'
        }
      ],
      responseTypeOptions: [
        {
          value: 'json',
          label: 'json'
        }, {
          value: 'html',
          label: 'HTML'
        }, {
          value: 'text',
          label: 'text'
        }, {
          value: 'xml',
          label: 'XML'
        }
      ]
    }
  },
  watch: {
  },
  created() {
    this.resetDebugApiLog() // 清除上次的 调试结果
  },
  mounted() {
  },
  methods: {
    // 装载数据
    loadData(id) {
      apiSelectById(this.eType, id).then(response => {
        this.activeName = 'element' // 设置当前 tab element
        this.setElement(response.data)
      })
    },
    // 点击新增用例按钮时调用此方法
    add(parent_id) {
      this.currentCatalogId = parent_id
      this.resetElement()
      this.activeName = 'element' // 设置当前 tab element
    },
    // 点击复制按钮时调用此方法
    copy(id) {
      // 根据要复制的用例 ID 查询用例信息
      apiSelectById(this.eType, id).then(response => {
        response.data.id = undefined
        response.data.name = response.data.name + ' - copy'
        if (response.data.apiParams) {
          response.data.apiParams.forEach(function(item) {
            item.id = undefined
          })
        }
        this.$nextTick(() => {
          this.setElement(response.data)
        })
      })
    },
    // 新增时初始化 element 数据
    resetElement() {
      this.element = {
        'projectId': this.$store.getters.projectId,
        'catalogId': this.currentCatalogId,
        'type': this.eType,
        'name': '',
        'url': '',
        'method': 'POST',
        'extra1': 'JSON',
        'apiParams': []
      }
      this.resetElementApiParam()

      this.$nextTick(() => {
        this.$refs['element'].clearValidate()
      })
    },
    // 新增时初始化 element.apiParams 数据
    resetElementApiParam() {
      this.headerSchema = {
        type: 'object',
        properties: {}
      }
      this.headerSchemaKey = Date.now() + 1
      this.cookiesSchema = {
        type: 'object',
        properties: {}
      }
      this.cookiesSchemaKey = Date.now() + 2
      this.paramsSchema = {
        type: 'object',
        properties: {}
      }
      this.paramsSchemaKey = Date.now() + 3
      this.bodySchema = {
        type: 'object',
        properties: {}
      }
      this.bodySchemaKey = Date.now() + 4
      this.assertSchema = {
        type: 'object',
        properties: {}
      }
      this.assertSchemaKey = Date.now() + 5
      this.mocksData = []
    },
    // 设置 element 数据（当服务端返回数据后有些类型不符需要在这个方法中转换）
    setElement(ele) {
      this.element = ele

      this.resetElementApiParam()
      for (const apiParam of this.element.apiParams) {
        switch (apiParam.kind) {
          case 1: // header
            this.headerSchema = JSON.parse(apiParam.des)
            break
          case 2: // params
            this.paramsSchema = JSON.parse(apiParam.des)
            break
          case 3: // body
            this.bodySchema = JSON.parse(apiParam.des)
            break
          case 4: // cookies
            this.cookiesSchema = JSON.parse(apiParam.des)
            break
          case 5: // assert
            this.assertSchema = JSON.parse(apiParam.des)
            break
          case 6: // mock
            this.mocksData = JSON.parse(apiParam.des)
            break
          default:
            console.log('Invalid apiParam.kind, kind: ' + apiParam.kind)
        }
      }
      this.$nextTick(() => {
        this.headerSchemaKey = Date.now()
        this.cookiesSchemaKey = Date.now()
        this.paramsSchemaKey = Date.now()
        this.bodySchemaKey = Date.now()
        this.assertSchemaKey = Date.now()

        this.$refs['element'].clearValidate()
      })
    },
    // schema 数据格式化（将改过的 schema 为 String 类型的数据，转成 json 对象）
    schemaDataConvert() {
      if (typeof this.headerSchema === 'string' || this.headerSchema instanceof String) {
        this.headerSchema = JSON.parse(this.headerSchema)
      }
      if (typeof this.cookiesSchema === 'string' || this.cookiesSchema instanceof String) {
        this.cookiesSchema = JSON.parse(this.cookiesSchema)
      }
      if (typeof this.paramsSchema === 'string' || this.paramsSchema instanceof String) {
        this.paramsSchema = JSON.parse(this.paramsSchema)
      }
      if (typeof this.bodySchema === 'string' || this.bodySchema instanceof String) {
        this.bodySchema = JSON.parse(this.bodySchema)
      }
      if (typeof this.assertSchema === 'string' || this.assertSchema instanceof String) {
        this.assertSchema = JSON.parse(this.assertSchema)
      }
      this.$nextTick(() => {
        this.headerSchemaKey = Date.now()
        this.cookiesSchemaKey = Date.now()
        this.paramsSchemaKey = Date.now()
        this.bodySchemaKey = Date.now()
        this.assertSchemaKey = Date.now()
      })
    },
    // raw checkbox change 事件
    handleRawCheckboxChange(check) {
      this.schemaDataConvert()
    },
    // 设置请求参数（apiParam）
    setApiParam(kind, name, schema) {
      if (typeof schema === 'string') {
        schema = JSON.parse(schema)
      }
      if (typeof schema === 'undefined' || typeof schema.properties === 'undefined' || typeof schema.properties !== 'object' || Object.keys(schema.properties).length === 0) { // schema 为空，不处理
        schema = {
          type: 'object',
          properties: {}
        }
      }
      let isExist = false
      for (const apiParam of this.element.apiParams) {
        if (apiParam.kind === kind) {
          apiParam.des = JSON.stringify(schema)
          isExist = true
          break
        }
      }
      if (!isExist) {
        this.element.apiParams.push({
          apiId: this.element.id,
          name: name,
          des: JSON.stringify(schema),
          paramType: 0,
          isRequired: true,
          kind: kind
        })
      }
    },
    // 设置 mocks 请求参数（apiParam）
    setApiMocksParam(kind, name, schema) {
      if (typeof schema === 'string') {
        schema = JSON.parse(schema)
      }
      let isExist = false
      for (const apiParam of this.element.apiParams) {
        if (apiParam.kind === kind) {
          apiParam.des = JSON.stringify(schema)
          isExist = true
          break
        }
      }
      if (!isExist) {
        this.element.apiParams.push({
          apiId: this.element.id,
          name: name,
          des: JSON.stringify(schema),
          paramType: 0,
          isRequired: true,
          kind: kind
        })
      }
    },
    // tab 切换
    handleTabClick(tab, event) {
      this.schemaDataConvert()
    },
    // 点击导入 curl
    handleImportCurl() {
      this.importCurlDialogFormVisible = true
      this.importCurlTextarea = ''
    },
    // 导入 curl
    importCurl() {
      const parse = require('@/components/ParseCurl/index')
      const curlParse = parse(this.importCurlTextarea)
      if (curlParse === undefined) {
        this.$message({ message: 'cURL 导入失败，无法识别的 cURL 格式', type: 'error' })
        return
      }
      apiCurlImport({ ignoreGenericHeader: this.ignoreGenericHeader, curl: curlParse }).then((response) => {
        response.data.projectId = this.element.projectId
        response.data.id = this.element.id
        response.data.catalogId = this.element.catalogId
        this.setElement(response.data)
        this.$message({ message: 'cURL 导入成功!', type: 'success' })
        this.importCurlDialogFormVisible = false
      })
    },
    // 点击 导出性能测试脚本
    handleExport() {
      this.exportDialogFormVisible = true
      this.exportTextarea = ''
      apiExport({ type: this.eType, id: this.element.id }).then((response) => {
        this.exportTextarea = response.data
      })
    },
    // 点击 导出性能测试脚本 弹框 复制 按钮
    handleExportCopy(event) {
      clip(this.exportTextarea, event)
    },
    // 点击导入 json
    handleImportJson() {
      this.dialogFormVisible = true
      this.importJsonStr = {}
      this.importJsonStrKey = Date.now()
    },
    // 导入 json
    importJson() {
      try {
        let json // 待导入的 json 对象
        if (typeof this.importJsonStr === 'object') {
          json = this.importJsonStr
        } else if (typeof this.importJsonStr === 'string') {
          json = JSON.parse(this.importJsonStr)
        }

        let t = GenerateSchema.json(json)
        delete t.$schema
        t = setSchemaDefaultValue(json, t) // 设置 schema 的默认值

        if (this.kindActiveName === 'Headers') {
          this.headerSchema = Object.assign({}, t)
          this.headerSchemaKey = Date.now()
        } else if (this.kindActiveName === 'Cookies') {
          this.cookiesSchema = Object.assign({}, t)
          this.cookiesSchemaKey = Date.now()
        } else if (this.kindActiveName === 'Params') {
          this.paramsSchema = Object.assign({}, t)
          this.paramsSchemaKey = Date.now()
        } else if (this.kindActiveName === 'Body') {
          this.bodySchema = Object.assign({}, t)
          this.bodySchemaKey = Date.now()
        } else if (this.kindActiveName === 'Assert') {
          this.assertSchema = Object.assign({}, t)
          this.assertSchemaKey = Date.now()
        }
        this.$message({ message: 'Json 导入成功!', type: 'success' })
        this.dialogFormVisible = false
      } catch (e) {
        this.$message.error('Json 导入失败：Json 格式错误！')
      }
    },
    // 保存 element 数据
    saveElement() {
      this.$refs['element'].validate((valid) => {
        if (valid) {
          this.element.type = this.eType

          this.setApiParam(1, 'header', this.headerSchema)
          this.setApiParam(2, 'params', this.paramsSchema)
          this.setApiParam(3, 'body', this.bodySchema)
          this.setApiParam(4, 'cookies', this.cookiesSchema)
          this.setApiParam(5, 'assert', this.assertSchema)
          this.setApiMocksParam(6, 'mock', this.mocksData)

          if (!this.element.id || this.element.id === 0) { // id = 0，新增
            // 跟目录设置 parentId = 0
            if (!this.element.catalogId) {
              this.element.catalogId = 0
            }
            create(this.element).then((response) => {
              this.element = response.data
              this.$emit('create', response.data)
              this.$message({ message: '添加成功!', type: 'success' })
            })
          } else { // 否则修改
            update(this.element).then((response) => {
              this.element = response.data
              this.$emit('update', response.data)
              this.$message({ message: '修改成功!', type: 'success' })
            })
          }
        }
      })
    },
    // 选择 JSON、FORM
    handleChangeExtra1(event) {
      this.$nextTick(() => {
        this.headerSchemaKey = Date.now()
        this.cookiesSchemaKey = Date.now()
        this.paramsSchemaKey = Date.now()
        this.bodySchemaKey = Date.now()
        this.assertSchemaKey = Date.now()
      })
    },
    // 点击 添加期望
    handleAddDesire() {
      this.dialogFormDesireVisible = true
      this.tmpDesireIndex = -1
      this.tmpDesire = {
        conditions: [{
          location: 'query',
          comparison: 'equal'
        }],
        responseCode: '200',
        responseType: 'json',
        responseBody: '{}'
      }
    },
    // 期望 点击 确定
    addDesire() {
      this.$refs['tmpDesireForm'].validate((valid) => {
        if (valid) {
          // 去除空行
          this.tmpDesire.conditions = this.tmpDesire.conditions.filter((item) => {
            if (Object.keys(item).length === 0) {
              return false
            }
            if ((item.location === undefined || item.location.trim().length === 0) ||
              (item.name === undefined || item.name.trim().length === 0) ||
              (item.comparison === undefined || item.comparison.trim().length === 0)) {
              return false
            }
            return true
          })

          if (this.tmpDesireIndex === -1) {
            this.mocksData.push(this.tmpDesire)
          } else {
            this.$set(this.mocksData, this.tmpDesireIndex, this.tmpDesire)
          }
          this.dialogFormDesireVisible = false
        }
      })
    },
    // 点击 mocks 操作中的 编辑
    handleEditDesire(index) {
      this.tmpDesireIndex = index
      this.tmpDesire = deepClone(this.mocksData[index])
      this.tmpDesire.conditions.push({
        location: 'query',
        comparison: 'equal'
      })
      this.dialogFormDesireVisible = true
    },
    // 点击删除 mocks table 中的一行数据
    delDesireTableRow(index) {
      this.mocksData.splice(index, 1) // 删除一行
    },
    // 滚动到最下后新增参数条件一行表格数据
    newConditionsTableRow() {
      this.tmpDesire.conditions.push({
        location: 'query',
        comparison: 'equal'
      })
      this.$nextTick(() => { // table 超出后滚动到最后
        this.$refs.stepsTable.bodyWrapper.scrollTop = this.$refs.stepsTable.bodyWrapper.scrollHeight
      })
    },
    // 删除参数条件 table 中的一行数据
    delConditionsTableRow(index) {
      this.tmpDesire.conditions.splice(index, 1) // 删除一行
    },
    // 点击 比较
    handleChangeComparison(row, event) {
      if (event === 'exists' || event === 'not_exist') {
        row.value = ''
      }
    },
    // 期望转中文
    conditionsToStr(conditions) {
      let str = ''
      str = str + conditions.location + ' 参数 ' + conditions.name + ' '
      for (const comparison of this.comparisonOptions) {
        if (comparison.value === conditions.comparison) {
          str = str + comparison.label + ' '
          break
        }
      }
      str = str + conditions.value
      return str
    },
    // 点击 history 按钮
    handleHistory() {
      this.historyDialogFormVisible = true
      this.$nextTick(() => {
        this.$refs.apiHistoryComponent.loadData(this.element.id)
      })
    },
    // 双击历史结果行
    dblclickResultRow(ele) {
      this.historyDialogFormVisible = false
      this.setElement(ele)
    },
    // 清除上次的 调试结果
    resetDebugApiLog() {
      this.debugApiLog = {
        request: {
          log: ''
        },
        response: {
          log: ''
        }
      }
    },
    // 点击发送
    handleSend() {
      this.$refs['element'].validate((valid) => {
        if (valid) {
          if (this.element.id === undefined) {
            this.$message({ message: '发送失败，请先保存接口后再点击发送按钮!', type: 'error' })
            return
          }

          this.resetDebugApiLog() // 清除上次的 调试结果

          this.element.type = this.eType

          this.setApiParam(1, 'header', this.headerSchema)
          this.setApiParam(2, 'params', this.paramsSchema)
          this.setApiParam(3, 'body', this.bodySchema)
          this.setApiParam(4, 'cookies', this.cookiesSchema)
          this.setApiParam(5, 'assert', this.assertSchema)
          this.setApiMocksParam(6, 'mock', this.mocksData)

          const tempData = {
            projectId: this.$store.getters.projectId,
            env: this.debugEnv,
            agentId: this.debugAgentId,
            api: this.element
          }
          apiDebug(tempData).then((response) => {
            const debugSessionId = response.data.sessionId
            const debugTimestamp = response.data.timestamp
            this.checkDebugStatusTimer = setInterval(() => {
              getApiDebugStatus(debugSessionId, debugTimestamp).then(response => {
                if (response.data.result) {
                  this.debugApiLog = response.data
                  if (response.data.response.status === 3) {
                    this.$message({ message: 'http 接口请求成功!', type: 'success' })
                  } else {
                    this.$message({ message: response.data.response.type === null ? '接口调试返回结果错误：' + response.data.request.type : '接口调试返回结果错误：' + response.data.response.type, type: 'error' })
                  }
                  clearInterval(this.checkDebugStatusTimer)
                }
              })
            }, 2000)
            this.$message({ message: '请求发送成功，等待返回结果!', type: 'success' })
          })
        }
      })
    }
  }
}
</script>
